home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / T U R B O Language / Turbo C Tools v6.0 / EXAMPLES / PULLMENU.C < prev    next >
Encoding:
C/C++ Source or Header  |  1989-03-31  |  15.6 KB  |  558 lines

  1. /**
  2. *    PULLMENU.C    Sample creation of a simple pull-down menu
  3. *            system.
  4. *
  5. *  This program displays a menu bar across the top of the screen (the
  6. *  "root" menu) which contains several items, each of which has an
  7. *  associated vertical "pulldown" menu associated with it.
  8. *
  9. *  The command line format is as follows:
  10. *
  11. *    pullmenu
  12. *
  13. *  The purpose of PULLMENU is to provide a working example of the
  14. *  proper method of construction and use of a pulldown menu system.
  15. *
  16. *  Version    6.00 (C)Copyright Blaise Computing Inc. 1989
  17. *
  18. **/
  19.  
  20. #include <ctype.h>
  21. #include <stdio.h>
  22.  
  23. #include <bkeybrd.h>
  24. #include <bkeys.h>
  25. #include <bmenu.h>
  26. #include <butil.h>
  27. #include <bscreens.h>
  28. #include <bvideo.h>
  29. #include <bmouse.h>
  30.  
  31.         /* Text color is intense white on blue.         */
  32. #define MYTEXTATR (utnybbyt (SC_BLUE, SC_WHITE | INTENSITY))
  33.  
  34.         /* Color of highlight bar is black text on a white  */
  35.         /* background.                        */
  36. #define MYHILATR  (utnybbyt (SC_WHITE, SC_BLACK))
  37.  
  38.         /* Color of "protected" items is green on blue.     */
  39. #define MYPROATR  (utnybbyt (SC_BLUE,  SC_GREEN))
  40.  
  41.         /* Color of menu borders is cyan on black.        */
  42. #define MYBORDATR (utnybbyt (SC_BLACK, SC_CYAN))
  43.  
  44.         /* Color of menu titles is the same as menu borders.*/
  45. #define MYTITATR  MYBORDATR
  46.  
  47. #define NUL    '\0'
  48. #define TRUE   1
  49. #define FALSE  0
  50.  
  51.         /* Constants returned by pulldown menu functions.   */
  52. #define MOVE_LEFT  -1
  53. #define MOVE_RIGHT  1
  54. #define STAY_PUT    0
  55.  
  56.         /* Terminate-on-error macro.                */
  57. #define exitBad()                             \
  58.     {                                     \
  59.     mohide(MO_HIDE);                         \
  60.     fprintf (stderr,                         \
  61.          "pullmenu: died with b_wnerr = %d in line %d",      \
  62.          b_wnerr, __LINE__);                     \
  63.     exit (b_wnerr);                          \
  64.     }
  65.  
  66. typedef struct            /* PULL_ITEM: Describes one item in a   */
  67. {                /* pulldown menu.                */
  68.     int   row;            /* The row on which the item is located.*/
  69.     char *pitem_text;        /* The item's text.                     */
  70.     char *pselection_keys;  /* The keys which will select the item. */
  71. } PULL_ITEM;
  72.  
  73. typedef struct            /* ROOT_ITEM: Describes one item in the */
  74. {                /* root menu.                */
  75.     int   column;        /* The item's column.                   */
  76.     char *pitem_text;        /* The item's text.                     */
  77.     char *pselection_keys;  /* The keys which will select the item. */
  78.     int   display_pulldown; /* Whether to display the item's        */
  79.                 /* pulldown automatically.            */
  80. } ROOT_ITEM;
  81.  
  82.         /* Constants describing the locations of the menu   */
  83.         /* items in the root menu.                */
  84. #define ITEM_ONE_COL    1
  85. #define ITEM_TWO_COL    12
  86. #define ITEM_THREE_COL    22
  87. #define ITEM_FOUR_COL    27
  88.  
  89.  
  90.         /* Item descriptors for the root menu.            */
  91. ROOT_ITEM root_items[] =
  92. {
  93.     {ITEM_ONE_COL,   " Language ", "Ll", 0},
  94.     {ITEM_TWO_COL,   " Machine ",  "Mm", 0},
  95.     {ITEM_THREE_COL, " OS ",       "Oo", 0},
  96.     {ITEM_FOUR_COL,  " Quit ",     "Qq", 0}
  97. };
  98. int num_root_items = sizeof(root_items) / sizeof(root_items[0]);
  99.  
  100.  
  101.         /* Item descriptors for the "Language" menu.        */
  102. PULL_ITEM language_items[] =
  103. {
  104.     {1, " C++        ", "Cc"},
  105.     {2, " C          ", "Cc"},
  106.     {3, " Pascal     ", "Pp"},
  107.     {4, " FORTRAN 77 ", "Ff"},
  108.     {5, " COBOL      ", "Cc"},
  109.     {6, " Logo       ", "Ll"},
  110.     {7, " Pilot      ", "Pp"}
  111. };
  112. int num_language_items = sizeof(language_items) /
  113.              sizeof(language_items[0]);
  114.  
  115.  
  116.         /* Item descriptors for the "Machine" menu.         */
  117. PULL_ITEM machine_items[] =
  118. {
  119.     {1, " Cray 2        ", "Cc"},
  120.     {2, " VAX 11/780    ", "Vv"},
  121.     {3, " IBM PS/2 80   ", "Ii"},
  122.     {4, " Apple //GS    ", "Aa"},
  123.     {5, " Sinclair ZX80 ", "Ss"}
  124. };
  125. int num_machine_items = sizeof(machine_items) /
  126.             sizeof(machine_items[0]);
  127.  
  128.  
  129.         /* Item descriptors for the "OS" menu.              */
  130. PULL_ITEM os_items[] =
  131. {
  132.     {1, " VMS          ", "Vv"},
  133.     {2, " UNIX 4.2 BSD ", "Uu"},
  134.     {3, " OS/2         ", "Oo"},
  135.     {4, " DOS 2.0      ", "Dd"},
  136.     {5, " CP/M 80      ", "Cc"}
  137. };
  138. int num_os_items = sizeof(os_items) / sizeof(os_items[0]);
  139.  
  140.  
  141.         /* Declare internal subroutines.            */
  142. BMENU *create_menu(int, int, PULL_ITEM *, int);
  143. int read_pulldown(BMENU *, int, int, PULL_ITEM *, int, int);
  144.  
  145.  
  146. void main ()
  147. {
  148.     int     mode, columns, active_page;
  149.     BMENU      *proot;
  150.     BMENU      *planguage_menu;
  151.     BMENU      *pmachine_menu;
  152.     BMENU      *pos_menu;
  153.     BORDER    border;
  154.     WHERE    where;
  155.     int     ch, scan;
  156.     int     row, col;
  157.     int     showrow, showcol;
  158.     int     done = FALSE;
  159.     ADAP_STATE    adapter_state;
  160.     PAGE_STATE    page_state;
  161.     int     current_item;
  162.     int     ret_value;
  163.     int     read_root = 1;
  164.     int     error_code;
  165.  
  166.         /* First we make certain that we are in 80 column   */
  167.         /* text video mode.                    */
  168.     scgetvid(&adapter_state);
  169.  
  170.     switch (adapter_state.mode)
  171.     {
  172.     case 2:
  173.     case 3:
  174.     case 7:
  175.     break;
  176.  
  177.     default:
  178.     fprintf (stderr, "Pullmenu: This demonstration works only "
  179.              "in 80 column\n");
  180.     fprintf (stderr, "          text modes (modes 2, 3, and 7)\n");
  181.     exit (1);
  182.     }
  183.  
  184.         /* Save the image and cursor of the current page to */
  185.         /* restore later.                    */
  186.     scsavepg(&page_state);
  187.  
  188.     scpclr();
  189.  
  190.         /* Create the menu data structures.            */
  191.     proot = mncreate(1, 80, MYTEXTATR, MYHILATR, MYPROATR, 0);
  192.     if (proot == NULL)
  193.     exitBad()
  194.  
  195.     planguage_menu = create_menu(9, 12, language_items,
  196.                  num_language_items);
  197.     if (planguage_menu == NULL)
  198.     exitBad ()
  199.  
  200.     pmachine_menu = create_menu(7, 15, machine_items,
  201.                 num_machine_items);
  202.     if (pmachine_menu == NULL)
  203.     exitBad ()
  204.  
  205.     pos_menu = create_menu(7, 14, os_items, num_os_items);
  206.     if (pos_menu == NULL)
  207.     exitBad ()
  208.  
  209.         /* Highlight the first item in each of the pulldown */
  210.         /* menus.                        */
  211.     mnhilite(planguage_menu, language_items[0].row, 0, MN_HIGHLIGHT);
  212.     mnhilite(pmachine_menu,  machine_items[0].row,  0, MN_HIGHLIGHT);
  213.     mnhilite(pos_menu,         os_items[0].row,        0, MN_HIGHLIGHT);
  214.  
  215.         /* Disable ESC key.                    */
  216.     if (mnkey (proot, 0, 0, KB_C_N_ESC, KB_S_N_ESC,
  217.            MN_ABORT, MN_DELETE) == NULL)
  218.     exitBad ()
  219.  
  220.         /* Set up items on the menu, and define         */
  221.         /* corresponding keys (upper and lower case of the  */
  222.         /* first letters of the items).             */
  223.     for (current_item = 0; current_item < num_root_items;
  224.      current_item++)
  225.     {
  226.     if (mnitmkey(proot, 0, root_items[current_item].column, 0,
  227.         root_items[current_item].pitem_text,
  228.         root_items[current_item].pselection_keys, MN_TRANSMIT) ==
  229.         NULL)
  230.     {
  231.         exitBad ()
  232.     }
  233.     }
  234.  
  235.         /* Figure out where to display the menu.        */
  236.     where.dev         = scmode(&mode, &columns, &active_page);
  237.     where.page         = active_page;
  238.     where.corner.row = 0;
  239.     where.corner.col = 0;
  240.  
  241.         /* Specify no border.                    */
  242.     border.type     = BBRD_NO_BORDER;
  243.  
  244.         /* Display the menu on the screen.            */
  245.     if (mndsplay (proot, &where, &border) == NULL)
  246.     exitBad ()
  247.  
  248.         /* Display a status bar at the bottom of the screen.*/
  249.     viatrect(scrows() - 1, 0, scrows() - 1, 79, SC_WHITE | INTENSITY,
  250.          SC_RED);
  251.     vidspmsg(scrows() - 1, 0, -1, -1, "Current selection:");
  252.  
  253.         /* If the mouse is present, enable its cursor.        */
  254.     if (MO_OK == mohide(MO_SHOW))
  255.     if (NULL == mnmstyle(proot, MN_MOU_CLICK, MO_LEFT))
  256.         exitBad ()
  257.  
  258.         /* Set up starting item for highlight bar.        */
  259.     current_item = 0;
  260.  
  261.     do
  262.     {
  263.         /* Leave this menu on the screen until they select  */
  264.         /* the "Quit" entry.                                */
  265.     row = 0;
  266.     col = root_items[current_item].column;
  267.  
  268.         /* If read_root is non-zero, then we need to read a */
  269.         /* user response from the root menu; otherwise        */
  270.         /* read a response from the pulldown associated     */
  271.         /* with the currently highlighted item.         */
  272.     if (read_root)
  273.     {
  274.         error_code = mnread (proot, row, col, &row, &col,
  275.                  &ch, &scan,
  276.                  MN_KEEP_HIGHLIGHT | MN_ALL_TRANSMIT);
  277.         if (error_code == MN_READ_AB)
  278.         {
  279.         /* If the user aborted the menu, ignore it.        */
  280.         b_wnerr = WN_NO_ERROR;
  281.         }
  282.         else
  283.         if (error_code)
  284.             exitBad ()
  285.  
  286.  
  287.         /* Find the index of the selected item.         */
  288.         for (current_item = 0; current_item < num_root_items;
  289.          current_item++)
  290.         {
  291.         if (root_items[current_item].column == col)
  292.             break;
  293.         }
  294.     }
  295.  
  296.         /* Set up location to show sub-menu.            */
  297.     showrow = where.corner.row + 2;
  298.     showcol = where.corner.col + col;
  299.  
  300.     ret_value = STAY_PUT;
  301.  
  302.         /* If the user transmitted an item, display its     */
  303.         /* pulldown; if it was the "Quit" item, quit.       */
  304.     if (read_root &&
  305.         ((ch == KB_C_N_ENTER) && (scan == KB_S_N_ENTER)) ||
  306.         ((ch == 0xff) && (scan == 0xff) &&
  307.          ((b_mnmoevent & MO_DCLICK) == MO_DCLICK)))
  308.     {
  309.         if (current_item == num_root_items - 1)
  310.         done = TRUE;
  311.         else
  312.         root_items[current_item].display_pulldown = 1;
  313.     }
  314.  
  315.         /* If the pulldown menu associated with this item   */
  316.         /* should be displayed, then display it and read a  */
  317.         /* user response from it.                */
  318.     if (root_items[current_item].display_pulldown)
  319.     {
  320.         /* Go do what was requested.                */
  321.         switch (col)
  322.         {
  323.         case ITEM_ONE_COL:
  324.         ret_value = read_pulldown(planguage_menu,
  325.                       showrow, showcol,
  326.                       language_items,
  327.                       num_language_items, 20);
  328.         break;
  329.  
  330.         case ITEM_TWO_COL:
  331.         ret_value = read_pulldown(pmachine_menu,
  332.                       showrow, showcol,
  333.                       machine_items,
  334.                       num_machine_items, 32);
  335.         break;
  336.  
  337.         case ITEM_THREE_COL:
  338.         ret_value = read_pulldown(pos_menu,
  339.                       showrow, showcol,
  340.                       os_items,
  341.                       num_os_items, 47);
  342.         break;
  343.         }
  344.         /* Assume that we're going to have to read a user   */
  345.         /* response from the main menu.             */
  346.         read_root = 1;
  347.  
  348.         /* If the key was a left or right arrow key, we     */
  349.         /* move the highlight bar the appropriate direction.*/
  350.         if ((ret_value == MOVE_LEFT) || (ret_value == MOVE_RIGHT))
  351.         {
  352.         /* First, make sure this item's pulldown will be    */
  353.         /* displayed next time it is highlighted.        */
  354.         root_items[current_item].display_pulldown = 1;
  355.  
  356.         /* Now unhighlight the current item and determine   */
  357.         /* which item should be highlighted next.        */
  358.         mnhilite(proot, 0, root_items[current_item].column,
  359.              MN_UNHIGHLIGHT);
  360.  
  361.         current_item = (current_item + ret_value +
  362.                 num_root_items) % num_root_items;
  363.  
  364.         /* Check to see if we need to read the root menu    */
  365.         /* next time around.                    */
  366.         if (root_items[current_item].display_pulldown)
  367.         {
  368.             read_root = 0;
  369.             mnhilite(proot, 0, root_items[current_item].column,
  370.                  MN_HIGHLIGHT);
  371.         }
  372.         }
  373.         else
  374.         root_items[current_item].display_pulldown = 0;
  375.     }
  376.  
  377.     } while (!done);
  378.  
  379.     mndstroy(proot);
  380.  
  381.         /* Turn mouse cursor off.                */
  382.     mohide(MO_HIDE);
  383.  
  384.         /* Restore cursor position and style.            */
  385.     scsetvid(&adapter_state);
  386.     screstpg(&page_state);
  387. }
  388.  
  389.  
  390. /**
  391. *
  392. * Name        READ_PULLDOWN -- Display and allow user selection from
  393. *                 a pulldown menu.
  394. *
  395. * Synopsis    ret_value = read_pulldown(pmenu, row, col,
  396. *                      pitems, num_items, msg_col);
  397. *
  398. *        int ret_value       The return value for the parent menu
  399. *                   to act on.
  400. *        BMENU *pmenu       The pulldown menu to read from.
  401. *        int row, col       Row and column where the upper
  402. *                   left corner of the menu's data
  403. *                   area should appear.
  404. *        PULL_ITEM *pitems  An array of item descriptors for
  405. *                   the menu.
  406. *        int num_items       The number of items in *pitems.
  407. *        int msg_col       The column at which to display a
  408. *                   message indicating which item was
  409. *                   selected.
  410. *
  411. *
  412. * Description    This function displays pmenu and waits for user input.
  413. *        If the user presses a left or right arrow key, it will
  414. *        return MOVE_LEFT or MOVE_RIGHT to its caller, as
  415. *        appropriate.  An abort key or mouse event will cause
  416. *        b_wnerr to be cleared, and the return code will be
  417. *        STAY_PUT.  A transmission key or mouse event causes
  418. *        a return value of STAY_PUT.
  419. *
  420. * Returns    ret_value   MOVE_LEFT, MOVE_RIGHT, or STAY_PUT.
  421. *
  422. **/
  423.  
  424.  
  425. int read_pulldown(pmenu, row, col, pitems, num_items, msg_col)
  426. BMENU      *pmenu;
  427. int       row;
  428. int       col;
  429. PULL_ITEM *pitems;
  430. int       num_items;
  431. int       msg_col;
  432. {
  433.     int           mode, columns, active_page;
  434.     BORDER          border;
  435.     WHERE          where;
  436.     int           ch, scan;
  437.     int           error_code;
  438.  
  439.         /* Figure out where to display the menu.        */
  440.     where.dev         = scmode(&mode, &columns, &active_page);
  441.     where.page         = 0;
  442.     where.corner.row = row;
  443.     where.corner.col = col;
  444.  
  445.         /* Make a border with no title.             */
  446.     border.type     = BBRD_SSSS;
  447.     border.attr     = MYBORDATR;
  448.     border.ch        = NUL;
  449.  
  450.         /* Display the menu on the screen.            */
  451.     if (mndsplay(pmenu, &where, &border) == NULL)
  452.     exitBad ()
  453.  
  454.         /* Read a response from the menu.            */
  455.     error_code = mnread(pmenu, 1, 0, &row, &col, &ch, &scan,
  456.             MN_KEEP_HIGHLIGHT | MN_REMOVE | MN_PREV_BAR);
  457.  
  458.     if (error_code == MN_READ_AB)
  459.     {
  460.     b_wnerr = WN_NO_ERROR;
  461.     return(STAY_PUT);
  462.     }
  463.     if (error_code)
  464.     exitBad ()
  465.  
  466.         /* Tell the caller whether a left or right arrow    */
  467.         /* key was hit.                     */
  468.     if ((ch == KB_C_N_LEFT) && (scan == KB_S_N_LEFT))
  469.     return(MOVE_LEFT);
  470.  
  471.     if ((ch == KB_C_N_RIGHT) && (scan == KB_S_N_RIGHT))
  472.     return(MOVE_RIGHT);
  473.  
  474.         /* Display a message indicating which item was        */
  475.         /* selected.                        */
  476.     if ((row - 1) < num_items)
  477.     vidspmsg(scrows() - 1, msg_col, -1, -1,
  478.          pitems[row -1].pitem_text);
  479.  
  480.         /* Tell the caller not to move left or right, and   */
  481.         /* not to call us immediately the next time our     */
  482.         /* root menu item is selected.                */
  483.     return(STAY_PUT);
  484. }
  485.  
  486.  
  487. /**
  488. *
  489. * Name        CREATE_MENU -- Create a vertical menu given its
  490. *                   dimensions and an array of its items.
  491. *
  492. * Synopsis    pmenu = create_menu(height, width, pitems, num_items);
  493. *
  494. *        BMENU *pmenu        Pointer to the newly created menu.
  495. *        int height,        The height and width of the menu to
  496. *            width        create.
  497. *        PULL_ITEMS *pitems  Array of pulldown menu item
  498. *                    descriptors.
  499. *        int num_items        Number of items in pitems.
  500. *
  501. * Description    This function constructs a menu given its dimensions
  502. *        and an array of item descriptors for its items.  It
  503. *        designates the left and right arrow keys to be
  504. *        transmission keys, and disables the ESC key.  It also
  505. *        sets the window up to use the "click" style of mouse
  506. *        events.
  507. *
  508. * Returns    pmenu    Pointer to the newly created menu, or NULL
  509. *            if an error occurs.
  510. *
  511. **/
  512.  
  513. BMENU *create_menu(height, width, pitems, num_items)
  514. int       height;
  515. int       width;
  516. PULL_ITEM *pitems;
  517. int       num_items;
  518. {
  519.     BMENU *pcreated;
  520.     int current_item;
  521.  
  522.     pcreated = mncreate(height, width, MYTEXTATR, MYHILATR,
  523.             MYPROATR, 0);
  524.     if (pcreated == NULL)
  525.     return(NULL);
  526.  
  527.         /* Change the left and right arrow keys.        */
  528.     if (mnkey(pcreated, 0, 0, KB_C_N_LEFT, KB_S_N_LEFT,
  529.            MN_TRANSMIT, MN_CHANGE) == NULL)
  530.     exitBad ()
  531.     if (mnkey(pcreated, 0, 0, KB_C_N_RIGHT, KB_S_N_RIGHT,
  532.            MN_TRANSMIT, MN_CHANGE) == NULL)
  533.     exitBad ()
  534.  
  535.         /* Disable ESC key.                    */
  536.     if (mnkey (pcreated, 0, 0, KB_C_N_ESC, KB_S_N_ESC,
  537.            MN_ABORT, MN_DELETE) == NULL)
  538.     exitBad ()
  539.  
  540.         /* Install mouse events.                */
  541.     if (NULL == mnmstyle(pcreated, MN_MOU_CLICK, MO_LEFT))
  542.     exitBad ()
  543.  
  544.         /* Now install all the specified items.         */
  545.     for (current_item = 0; current_item < num_items; current_item++)
  546.     {
  547.     if (mnitmkey(pcreated, pitems[current_item].row, 0, 0,
  548.         pitems[current_item].pitem_text,
  549.         pitems[current_item].pselection_keys, MN_TRANSMIT) ==
  550.         NULL)
  551.     {
  552.         exitBad ()
  553.     }
  554.     }
  555.  
  556.     return(pcreated);
  557. }
  558.